/*
 * planificador.c
 *
 *  Created on: 19/09/2011
 *      Author: utn_so
 */
/*
 * Primero se levanta el archivo de configuracion y se ve si se conecta a modo de Servidor
 * (conecta con FS) o cliente (conecta con RAID).
 * 	Si es directamente con el FIle System, deberia conectarse y levantar la consola, luego los
 * 		pedidos del Fs se deberian encolar y el proceso principal deberia fijarse de sacarlo y
 * 		escribir o leer segun corresponda
 * 	Si es con un RAID, deberia conectarse al RAID y esperar a que el select de el ok a aceptar el
 * 		PPD, luego levantar la consola, y es trabajo del raid encolar los pedidos ya que la fuincion de colar y
 * 		desencolar del PPD solo es directamente,
 * 		ya que solo se usan colas en ppd para sincronizar con otro disco
 */
#include "planificador.h"
#define SOCK_PATH "echo_socket"
#define MAXDATASIZE 100 //el número máximo de datos en bytes
#define COLA_PENDIENTE_CONEXIONES  5

int32_t cuantosSectoresEscribi=0;

int32_t main(int32_t argc, char *argv[]) {
	//Variable de sockets y consola
	int32_t longitud=-1,idProceso = 0;
	//variables de hilos
	int32_t valorRetornoHilo;
	int32_t valorRetornoHiloConector;
	long hiloId;
	long hiloId2=2;
	//Variable de mapeo
	char *map=NULL;
	char lecturaDeBytechar[513];
	struct stat *punteroEstructuraSTAT;
	uint64_t *descriptorArchivo;
	//variables algoritmos planificador
	direccionSCAN=1;
	posicionCabezal=0;
	sectoresTotalesDeDisco=0;

	hiloId=1;
	int *descriptorSocket=NULL;



	int i;
	pthread_mutex_init(&mutexSincro,NULL);
	pthread_mutex_init(&mutexArchConfig,NULL);
	pthread_mutex_init(&mutexInfoSector,NULL);//TODO declaracion sem1 main
	pthread_mutex_init(&mutexInfoSector2,NULL);//TODO declaracion sem2 main
	pthread_mutex_init(&mutexPtroFteEscribir,NULL);//TODO declaracion sem3 main
	pthread_mutex_init(&mutexBackup1,NULL);
	//COMIENZO DEL PROGRAMA PRINCIPAL
	//[*] Leo el archivo de configuracion
	pthread_mutex_lock(&mutexArchConfig);
		 if (iniciarEstructuraConfiguracion()!=1){
			  	  printf("No se pudo procesar el archivo de configuracion");
			  	  return 1;
			  	}
	pthread_mutex_unlock(&mutexArchConfig);
		 sectoresTotalesDeDisco=stConfig.iCabezal*stConfig.iCantidadPistas*stConfig.iSectoresPista;
		//Pruebo que todos los valores esten Ok, se puede borrar
		/*printf("Activvar Logs? %s\n",stConfig.cActivarLogs);
		printf("Algoritmo de planificacion %s\n",stConfig.cAlgoritmoPlan);
		printf("IP escucha %s\n",stConfig.cIpEscucha);
		printf("modo de inicio C o L? %s\n",stConfig.cModoInicio);
		printf("path sock unix %s\n",stConfig.cPathSocketUnix);
		printf("cabezal %d\n",stConfig.iCabezal);
		printf("cant psita %d\n",stConfig.iCantidadPistas);
		printf("id disco %d\n",stConfig.iIdDisco);
		printf("puerto escucha %d\n",stConfig.iPuertoEscucha);
		printf("RPM %d\n",stConfig.iRPM);
		printf("Sectores por pista %d\n",stConfig.iSectoresPista);
		printf("tiemp escritura %d\n",stConfig.iTiempoEscritura);
		printf("tiempo lectura %d\n",stConfig.iTiempoLectura);
		printf("tiempo salto pista %d\n",stConfig.iTiempoSaltoPistas);
*/

	/*	//leo datos por medio del archivo de configuracion y los guardo en una estructura para reutilizarlos luego
		if(leoArchivo(&punteroEstructuraConfiguracion)==0) {
			printf("No se pudo cargar los datos del archivo de configuracion");
		}
		printf("Se leyó correctamente el archivo de configuracion\n");*/
	idProceso = fork();
	if (idProceso == 0) {
		/*Proceso Hijo*/
		printf("El PID de mi proceso padre es %d\n", getppid());
		sleep(1);
		execv ("/home/utn_so/Desarrollo/PPD2/ConsolaPPD/Release/ConsolaPPD", argv);
		exit(1);
	} else {
		/* Proceso Padre */
		if(idProceso < 0){
//TODO poner el error de que hizo mal el fork
			}

		else{
			printf("Mi PID es el %d y el de mi hijo es %d\n", getpid(), idProceso);
			descriptorSocketPlanificador = socketUnix_preparar();
			socketUnix_bindear(descriptorSocketPlanificador, estructuraSocketPlanificador,longitud);
			socketUnix_escuchar(descriptorSocketPlanificador, COLA_PENDIENTE_CONEXIONES);
			valorRetornoHilo =hilo_crear(hiloId);
			valorRetornoHiloConector =hilo_crear2(hiloId2);


			pthread_mutex_lock(&mutexSincro);
			punteroEstructuraLeer=punteroFrenteLeer;
			pthread_mutex_unlock(&mutexSincro);

			punteroEstructuraSTAT=(struct stat*)calloc(1,sizeof(struct stat));
			Archivo_mapear(&descriptorArchivo,&map,&punteroEstructuraSTAT);

			struct estructuraEscribir *punteroEscrituraAux;
			struct estructuraLeer *punteroLecturaAux;
			while(1){

				if (memcmp(stConfig.cAlgoritmoPlan, "NSCAN", strlen("NSCAN")) == 0) {
					for(i = 0; (i < 50) && punteroFrenteLeer; i++){
						punteroLecturaAux = primeros10NodosLectura(&punteroFrenteLeer);
						while(punteroLecturaAux){
							lectura_atender(&punteroLecturaAux, map,lecturaDeBytechar);
							usleep(stConfig.iTiempoLectura);
						//	if(punteroLecturaAux->numeroSector == 900000 && punteroLecturaAux->siguiente == NULL){
							//	printf("SE ATIENDE EL 9000O0 Y NO HAY MAS NODOS");
						//	}else if(punteroLecturaAux->numeroSector == 900000 && punteroLecturaAux->siguiente){
							//	printf("SE ATIENDE EL 9000000 Y HAY MAAS NODOS, ESTAMOS AL HORNO");
							//}
						}
					}
				}else{
					pthread_mutex_lock(&mutexSincro);
					punteroLecturaAux = punteroFrenteLeer;
					pthread_mutex_unlock(&mutexSincro);
					for(i=0; (i < 500) && punteroLecturaAux != NULL;i++){
						if(punteroLecturaAux->numeroSector == 900000 && punteroLecturaAux->siguiente == NULL){
							printf("SE ATIENDE EL 9000O0 Y NO HAY MAS NODOS");
						}else if(punteroLecturaAux->numeroSector == 900000 && punteroLecturaAux->siguiente){
							printf("SE ATIENDE EL 9000000 Y HAY MAAS NODOS, ESTAMOS AL HORNO");
						}
						lectura_atender(&punteroLecturaAux, map,lecturaDeBytechar);
						usleep(stConfig.iTiempoLectura);

					}
				}


			/*	if (memcmp(stConfig.cAlgoritmoPlan, "NSCAN", strlen("NSCAN")) == 0) {
					punteroLecturaAux = primeros500NodosLectura(&punteroFrenteLeer);
				}else{
					pthread_mutex_lock(&mutexSincro);
					punteroLecturaAux = punteroFrenteLeer;
					pthread_mutex_unlock(&mutexSincro);
				}
				for(i=0;(i<500)&&punteroLecturaAux!=NULL;i++){
					lectura_atender(&punteroLecturaAux, map,lecturaDeBytechar);
					usleep(stConfig.iTiempoLectura);
				}*/



				if (memcmp(stConfig.cAlgoritmoPlan, "NSCAN", strlen("NSCAN")) == 0) {
						punteroEscrituraAux = primeros500NodosEscritura(&punteroFrenteEscribir);
					}else{
						pthread_mutex_lock(&mutexPtroFteEscribir);
						punteroEscrituraAux = punteroFrenteEscribir;//TODO sem3
						pthread_mutex_unlock(&mutexPtroFteEscribir);
					}
				for(i=0;(i<500)&&punteroEscrituraAux!=NULL;i++){
					escritura_atender(&punteroEscrituraAux,&map,&punteroEstructuraSTAT);
					usleep(stConfig.iTiempoEscritura);
					/*if (cuantosSectoresEscribi%200==0){
						printf("cuantosSectoresEscribi %d\n",cuantosSectoresEscribi);
					}*/
					//nodoColaEscritura_liberar(&punteroFrenteEscribir,&punteroFinEscribir);
				}
			}

			Archivo_desmapear(&descriptorArchivo,&map,&punteroEstructuraSTAT);

			char systemCall[30];
			memset(systemCall,'\0',sizeof(systemCall));
			sprintf(systemCall,"kill -9 %d",idProceso);
			system(systemCall);
		}

		/*punteroEstructuraSTAT=(struct stat*)calloc(1,sizeof(struct stat));
		Archivo_mapear(&descriptorArchivo,&map,&punteroEstructuraSTAT);
		Archivo_escribir(3, "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901",&map,&punteroEstructuraSTAT);
		Archivo_escribir(5, "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901",&map,&punteroEstructuraSTAT);
		Archivo_leer(3,lecturaDeBytechar,map);
		printf("lecturaDeBytechar %s\n",lecturaDeBytechar);
		Archivo_leer(5,lecturaDeBytechar,map);
		printf("lecturaDeBytechar %s\n",lecturaDeBytechar);
		Archivo_desmapear(&descriptorArchivo,&map,&punteroEstructuraSTAT);
		exit(0);

*/
		while(1){

		}
	}

	descriptorSocket=(int*)calloc(1,100);

	printf("modo de conexion: %s\n",stConfig.cModoInicio);
	/*
	//Determina si se ejecutará como Cliente o Servidor
	if (strcmp(punteroEstructuraConfiguracion->cModoInicio ,"L")==0) {
		printf("Me ejecuto como servidor!\n");
		struct sockaddr_in server;
		// Para la informacion de la direccion del servidor.
		struct sockaddr_in client;
		if (!crearConexionConSocket(puertoFSSyDisco, &ficheroServer, &server)) {
			printf("No se pudo crear la conexion con el socket y dejarlo listo para escuchar conexiones entrantes.\n");
			return -1;
		}
		printf("Aplicacion levantada en: IP=%s; Port=%d.\n", inet_ntoa(server.sin_addr), puertoFSSyDisco);
		printf("PPD escuchando conexiones entrantes...\n");
		//Esperar conexion del FS
		while(sigue) {
			tamanoDeEstructuraSocket= sizeof(struct sockaddr_in);
			if((ficheroClient=accept(ficheroServer,(struct sockaddr *)&client,&tamanoDeEstructuraSocket))==-1) {
				printf("error en accept");
				exit(-1);
			}
			char *mensaje = "Bienvenido a mi servidor.\n";
			printf("Se obtuvo una conexión desde %s!\n", inet_ntoa(client.sin_addr));
			send(ficheroClient, mensaje,strlen(mensaje),0);
			//Conectar
			//Chequear pedidos de fs y encolarlos
			//Escribir y leer sectores
			//Chequear pedidos de consola y encolarlos
			//Escribir y leer sectores
			close(ficheroClient);
		}
	} else {
		if (strcmp(punteroEstructuraConfiguracion->cModoInicio ,"C")==0) {
			//Esperar conexion del RAID
			printf("Me ejecuto como cliente!\n");
			//Si se ejecuta como Cliente, se comunica con proceso RAID
			if(conectar(&descriptorSocket, punteroEstructuraConfiguracion->cIpRaid, punteroEstructuraConfiguracion->iPuertoRaid)==1) {
				printf("Me conecté!\n");
			} else {
				printf("No se pudo establecer la conexión!\n");
			}
			if((numbytes=recv(descriptorSocket,bufferDeMensaje,MAXDATASIZE,0))==-1) {
				printf("Error en recv()\n");
				exit(-1);
			}
			bufferDeMensaje[numbytes]='\0';
			printf("Mensaje del servidor: %s\n", bufferDeMensaje);
			//Conectar
			//Chequear pedidos de consola y encolarlos
			//Escribir y leer sectores
			close(descriptorSocket);
		} else {
			printf("valor invalido en el archivo de configuracion\n");
		}
	}
*/
		return 0;
}
/*
* Conecta con un servidor remoto a traves de socket INET
*/
